/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

#include "zbxcommon.h"

#ifdef HAVE_OPENIPMI

#include "ipmi_protocol.h"

#include "zbxserialize.h"
#include "zbxcacheconfig.h"

zbx_uint32_t	zbx_ipmi_serialize_request(unsigned char **data, zbx_uint64_t hostid, zbx_uint64_t objectid,
		const char *addr, unsigned short port, signed char authtype, unsigned char privilege,
		const char *username, const char *password, const char *sensor, int command, const char *key)
{
	unsigned char		*ptr;
	char			*user, *pwd;
	zbx_uint32_t		data_len, addr_len, username_len, password_len, sensor_len, key_len;

	addr_len = strlen(addr) + 1;
	user = zbx_strdup(NULL, username);
	pwd = zbx_strdup(NULL, password);

	zbx_dc_um_handle_t	*um_handle_secure = zbx_dc_open_user_macros_secure();
	zbx_dc_expand_user_and_func_macros(um_handle_secure, &user, &hostid, 1, NULL);
	zbx_dc_expand_user_and_func_macros(um_handle_secure, &pwd, &hostid, 1, NULL);
	zbx_dc_close_user_macros(um_handle_secure);

	username_len = strlen(user) + 1;
	password_len = strlen(pwd) + 1;
	sensor_len = strlen(sensor) + 1;
	key_len = NULL != key ? strlen(key) + 1 : 0;

	data_len = sizeof(zbx_uint64_t) + sizeof(short) + sizeof(char) * 2 + addr_len + username_len + password_len +
			sensor_len + key_len + sizeof(zbx_uint32_t) * 5 + sizeof(int);

	*data = (unsigned char *)zbx_malloc(NULL, data_len);
	ptr = *data;
	ptr += zbx_serialize_uint64(ptr, objectid);
	ptr += zbx_serialize_str(ptr, addr, addr_len);
	ptr += zbx_serialize_short(ptr, port);
	ptr += zbx_serialize_char(ptr, authtype);
	ptr += zbx_serialize_char(ptr, privilege);
	ptr += zbx_serialize_str(ptr, user, username_len);
	ptr += zbx_serialize_str(ptr, pwd, password_len);
	ptr += zbx_serialize_str(ptr, sensor, sensor_len);
	ptr += zbx_serialize_int(ptr, command);
	(void)zbx_serialize_str(ptr, key, key_len);

	zbx_free(user);
	zbx_free(pwd);

	return data_len;
}

void	zbx_ipmi_deserialize_request(const unsigned char *data, zbx_uint64_t *objectid, char **addr,
		unsigned short *port, signed char *authtype, unsigned char *privilege, char **username, char **password,
		char **sensor, int *command, char **key)
{
	zbx_uint32_t	value_len;

	data += zbx_deserialize_uint64(data, objectid);
	data += zbx_deserialize_str(data, addr, value_len);
	data += zbx_deserialize_short(data, port);
	data += zbx_deserialize_char(data, authtype);
	data += zbx_deserialize_char(data, privilege);
	data += zbx_deserialize_str(data, username, value_len);
	data += zbx_deserialize_str(data, password, value_len);
	data += zbx_deserialize_str(data, sensor, value_len);
	data += zbx_deserialize_int(data, command);
	(void)zbx_deserialize_str(data, key, value_len);
}

void	zbx_ipmi_deserialize_request_objectid(const unsigned char *data, zbx_uint64_t *objectid)
{
	(void)zbx_deserialize_uint64(data, objectid);
}

zbx_uint32_t	zbx_ipmi_serialize_result(unsigned char **data, const zbx_timespec_t *ts, int errcode,
		const char *value)
{
	unsigned char	*ptr;
	zbx_uint32_t	data_len, value_len;

	value_len = NULL != value ? strlen(value) + 1 : 0;

	data_len = value_len + sizeof(zbx_uint32_t) + sizeof(int) * 3;
	*data = (unsigned char *)zbx_malloc(NULL, data_len);

	ptr = *data;
	ptr += zbx_serialize_int(ptr, ts->sec);
	ptr += zbx_serialize_int(ptr, ts->ns);
	ptr += zbx_serialize_int(ptr, errcode);
	(void)zbx_serialize_str(ptr, value, value_len);

	return data_len;
}

void	zbx_ipmi_deserialize_result(const unsigned char *data, zbx_timespec_t *ts, int *errcode, char **value)
{
	int	value_len;

	data += zbx_deserialize_int(data, &ts->sec);
	data += zbx_deserialize_int(data, &ts->ns);
	data += zbx_deserialize_int(data, errcode);
	(void)zbx_deserialize_str(data, value, value_len);
}

#endif
